import pygame
import random
import json
import os
from collections import deque

# 初始化pygame
pygame.init()

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GRAY = (200, 200, 200)

# 游戏设置
GRID_SIZE = 20
GRID_WIDTH = 30
GRID_HEIGHT = 20
SCREEN_WIDTH = GRID_SIZE * GRID_WIDTH
SCREEN_HEIGHT = GRID_SIZE * GRID_HEIGHT + 200  # 增加UI区域高度
GAME_AREA_HEIGHT = GRID_SIZE * GRID_HEIGHT

# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("自动贪吃蛇")

# 游戏时钟
clock = pygame.time.Clock()

# 排行榜文件
HIGH_SCORES_FILE = "high_scores.json"


class SnakeGame:
    def __init__(self):
        self.reset_game()
        self.load_high_scores()

    def reset_game(self):
        # 蛇的初始位置和长度
        self.snake = deque([(GRID_WIDTH // 2, GRID_HEIGHT // 2)])
        self.direction = (1, 0)  # 初始向右移动
        self.next_direction = (1, 0)

        # 生成食物
        self.food = self.generate_food()

        # 游戏状态
        self.score = 0
        self.game_over = False
        self.game_speed = 10  # 默认游戏速度

    def generate_food(self):
        while True:
            food = (random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1))
            if food not in self.snake:
                return food

    def load_high_scores(self):
        self.high_scores = []
        if os.path.exists(HIGH_SCORES_FILE):
            with open(HIGH_SCORES_FILE, 'r') as f:
                self.high_scores = json.load(f)

    def save_high_scores(self):
        with open(HIGH_SCORES_FILE, 'w') as f:
            json.dump(self.high_scores, f)

    def add_high_score(self, score):
        self.high_scores.append(score)
        self.high_scores.sort(reverse=True)
        self.high_scores = self.high_scores[:5]  # 只保留前5条记录
        self.save_high_scores()

    def auto_move(self):
        # 改进的自动寻路算法，考虑蛇身避障和路径预测
        head_x, head_y = self.snake[0]
        food_x, food_y = self.food

        # 计算食物相对于蛇头的位置
        dx = food_x - head_x
        dy = food_y - head_y

        # 可能的移动方向
        possible_directions = []

        # 检查四个方向的可行性
        for direction in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
            # 不能反向移动
            if (direction[0] == -self.direction[0] and direction[1] == -self.direction[1]):
                continue

            # 计算新位置
            new_x = head_x + direction[0]
            new_y = head_y + direction[1]

            # 检查边界和蛇身碰撞
            if (new_x < 0 or new_x >= GRID_WIDTH or
                    new_y < 0 or new_y >= GRID_HEIGHT or
                    (new_x, new_y) in self.snake):
                continue

            # 预测未来几步路径，避免陷入U型陷阱
            safe = True
            temp_x, temp_y = new_x, new_y
            temp_snake = deque([(temp_x, temp_y)] + list(self.snake)[:-1])

            # 模拟移动3步，检查是否会陷入死路
            for _ in range(3):
                # 计算下一步可能的方向
                next_dirs = []
                for d in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
                    # 不能反向移动
                    if (d[0] == -direction[0] and d[1] == -direction[1]):
                        continue

                    nx = temp_x + d[0]
                    ny = temp_y + d[1]

                    # 检查边界和蛇身碰撞
                    if (nx < 0 or nx >= GRID_WIDTH or
                            ny < 0 or ny >= GRID_HEIGHT or
                            (nx, ny) in temp_snake):
                        continue

                    next_dirs.append(d)

                # 如果没有可行方向，标记为不安全
                if not next_dirs:
                    safe = False
                    break

                # 选择第一个可行方向继续模拟
                temp_x += next_dirs[0][0]
                temp_y += next_dirs[0][1]
                temp_snake.appendleft((temp_x, temp_y))
                temp_snake.pop()

            if not safe:
                continue

            # 计算到食物的距离
            dist = abs(new_x - food_x) + abs(new_y - food_y)
            possible_directions.append((dist, direction))

        # 如果有可行方向
        if possible_directions:
            # 选择距离食物最近的方向
            possible_directions.sort()
            self.next_direction = possible_directions[0][1]
        else:
            # 没有可行方向，随机选择一个方向
            self.next_direction = self.direction

    def update(self):
        if self.game_over:
            return

        # 自动寻路
        self.auto_move()
        self.direction = self.next_direction

        # 移动蛇
        head_x, head_y = self.snake[0]
        new_x = head_x + self.direction[0]
        new_y = head_y + self.direction[1]

        # 检查碰撞
        if (new_x < 0 or new_x >= GRID_WIDTH or
                new_y < 0 or new_y >= GRID_HEIGHT or
                (new_x, new_y) in self.snake):
            self.game_over = True
            self.add_high_score(self.score)
            return

        # 移动蛇
        self.snake.appendleft((new_x, new_y))

        # 检查是否吃到食物
        if (new_x, new_y) == self.food:
            self.score += 1
            self.food = self.generate_food()
        else:
            self.snake.pop()

    def draw(self):
        # 绘制游戏区域背景
        screen.fill(BLACK)
        pygame.draw.rect(screen, WHITE, (0, 0, SCREEN_WIDTH, GAME_AREA_HEIGHT))

        # 绘制蛇
        for segment in self.snake:
            x, y = segment
            pygame.draw.rect(screen, GREEN,
                             (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE))

        # 绘制蛇头
        head_x, head_y = self.snake[0]
        pygame.draw.rect(screen, BLUE,
                         (head_x * GRID_SIZE, head_y * GRID_SIZE, GRID_SIZE, GRID_SIZE))

        # 绘制食物
        food_x, food_y = self.food
        pygame.draw.rect(screen, RED,
                         (food_x * GRID_SIZE, food_y * GRID_SIZE, GRID_SIZE, GRID_SIZE))

        # 绘制UI区域
        pygame.draw.rect(screen, GRAY, (0, GAME_AREA_HEIGHT, SCREEN_WIDTH, 200))

        # 显示分数
        font = pygame.font.SysFont(None, 30)
        score_text = font.render(f"Score: {self.score}", True, BLACK)
        screen.blit(score_text, (10, GAME_AREA_HEIGHT + 10))

        # 显示重新开始按钮
        restart_button = pygame.Rect(SCREEN_WIDTH - 120, GAME_AREA_HEIGHT + 10, 100, 30)
        pygame.draw.rect(screen, BLUE, restart_button)
        restart_text = font.render("Restart", True, WHITE)
        screen.blit(restart_text, (SCREEN_WIDTH - 110, GAME_AREA_HEIGHT + 15))

        # 绘制速度控制按钮
        pygame.draw.rect(screen, GREEN, (SCREEN_WIDTH - 240, GAME_AREA_HEIGHT + 10, 50, 30))
        speed_up_text = font.render("+", True, WHITE)
        screen.blit(speed_up_text, (SCREEN_WIDTH - 230, GAME_AREA_HEIGHT + 15))

        pygame.draw.rect(screen, RED, (SCREEN_WIDTH - 180, GAME_AREA_HEIGHT + 10, 50, 30))
        speed_down_text = font.render("-", True, WHITE)
        screen.blit(speed_down_text, (SCREEN_WIDTH - 170, GAME_AREA_HEIGHT + 15))

        # 显示排行榜
        high_scores_text = font.render("High Scores:", True, WHITE)
        screen.blit(high_scores_text, (10, GAME_AREA_HEIGHT + 50))

        for i, score in enumerate(self.high_scores[:5]):
            score_text = font.render(f"{i + 1}. {score}", True, WHITE)
            screen.blit(score_text, (10, GAME_AREA_HEIGHT + 80 + i * 40))

        # 游戏结束显示
        if self.game_over:
            font = pygame.font.SysFont(None, 50)
            game_over_text = font.render("Game Over!", True, RED)
            screen.blit(game_over_text,
                        (SCREEN_WIDTH // 2 - 100, GAME_AREA_HEIGHT // 2 - 25))


# 主游戏循环
def main():
    game = SnakeGame()
    running = True

    # 定义速度控制按钮
    speed_up_button = pygame.Rect(SCREEN_WIDTH - 240, GAME_AREA_HEIGHT + 10, 50, 30)
    speed_down_button = pygame.Rect(SCREEN_WIDTH - 180, GAME_AREA_HEIGHT + 10, 50, 30)

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.MOUSEBUTTONDOWN:
                # 检查是否点击了重新开始按钮
                mouse_x, mouse_y = pygame.mouse.get_pos()
                restart_button = pygame.Rect(SCREEN_WIDTH - 120, GAME_AREA_HEIGHT + 10, 100, 30)
                if restart_button.collidepoint(mouse_x, mouse_y):
                    game.reset_game()
                elif speed_up_button.collidepoint(mouse_x, mouse_y):
                    game.game_speed = min(100, game.game_speed + 5)
                elif speed_down_button.collidepoint(mouse_x, mouse_y):
                    game.game_speed = max(2, game.game_speed - 5)

        game.update()
        game.draw()

        pygame.display.flip()
        clock.tick(game.game_speed)  # 使用变量控制游戏速度

    pygame.quit()


if __name__ == "__main__":
    main()

